'''
Description: 
Author: Zilu
Date: 2021-11-12 13:37:47
Version: 
LastEditTime: 2021-11-12 14:29:34
LastEditors: Zilu
'''

# 摘要算法又称哈希、散列算法，通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest
# 计算f(data)很容易，但通过digest反推data却非常困难

# 常见摘要算法 MD5 速度很快，生成 128 bit的密文
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('ascii'))
md5
print(md5.hexdigest())

# 数据量较大，可以分块多次调用update()，结果相同
md5 = hashlib.md5()
md5.update('how to use md5 '.encode('ascii'))
md5.update('in python hashlib?'.encode('utf-8'))
md5
print(md5.hexdigest())

md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib.'.encode('ascii'))
md5
print(md5.hexdigest())

# 另一种是SHA1，其使用和MD5类似，不过生成160bits的密文
sha1 = hashlib.sha1()
sha1.update('how to use md5 '.encode('ascii'))
sha1.update('in python hashlib?'.encode('utf-8'))
sha1
print(sha1.hexdigest())

# 比SHA1更安全的算法是SHA256和SHA512，不过越安全的算法不仅越慢，而且摘要长度更长。

# 练习：设计一个验证用户登录的函数，根据用户输入的口令是否正确，返回True或False，使用MD5
db = {
    'michael': 'e10adc3949ba59abbe56e057f20f883e',
    'bob': '878ef96e86145580c38c87f0410ad153',
    'alice': '99b1c2188db85afee403b1536010c2c9'
}

def login(user, password:str):
    return hashlib.md5(password.encode('ascii')).hexdigest() == db[user]


# 由于常用口令的MD5值很容易被计算出来，
# 所以，要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5，
# 这一方法通过对原始口令加一个复杂字符串来实现，俗称“加盐”：
def calMD5(password):
    return getMD5(password + 'the-Salt')

def getMD5(passwordWithSalt):
    pass

# 假定用户无法修改登录名，就可以通过把登录名作为Salt的一部分来计算MD5，
# 从而实现相同口令的用户也存储不同的MD5。

# 练习：根据用户输入的登录名和口令模拟用户注册，计算更安全的MD5
import hashlib, random
class User(object):
    def __init__(self,username,password) -> None:
        super().__init__()
        self.username = username
        # chr 函数转换成Unicode字符
        self.salt = ''.join([chr(random.randint(48, 122)) for i in range(20)])
        self.password = self.getMD5(username + password + self.salt)

    def getMD5(self, password:str):
        return hashlib.md5(password.encode('ascii')).hexdigest()

db = {
    'michael': User('michael', '123456'),
    'bob': User('bob', 'xyz999'),
    'alice': User('alice', 'alice2008'),
    'david': User('david', '123456')
}

def login(user, password):
    return db[user].password == db[user].getMD5(user+password+db[user].salt)



